﻿#pragma once

#include <wtypesbase.h>
#include <tchar.h>
#include <string>
#include <vector>

#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

class CPathUtils
{
public:

    // 
    // @brief: 获取当前进程完全路径
    // @ret: 当前进程完全路径 如 D:\Software\HxDPortableSetup.exe
    static _tstring GetCurrentModulePath();

    // 
    // @brief: 获取当前进程所在目录
    // @ret: 当前进程所在目录 如 D:\Software
    static _tstring GetCurrentModuleDir();

    // 
    // @brief: 获取当前进程名
    // @ret: 当前进程名 如 HxDPortableSetup.exe
    static _tstring GetCurrentModuleName(bool bHasExt = false);

    // 
    // @brief: 获取文件所在文件夹
    // @param: strPath     文件名, 如: D:\Software\HxDPortableSetup.exe
    // @ret: 文件夹        如 D:\Software
    static _tstring GetFileDir(const _tstring& strPath);

    // 
    // @brief: 获取文件名
    // @param: strPath     文件名, 如: D:\Software\HxDPortableSetup.exe
    // @param: bHasExt     是否包含扩展名
    // @ret: 文件夹        如 HxDPortableSetup
    static _tstring GetFileName(const _tstring& strPath, bool bHasExt = false);

    // 
    // @brief: 获取文件扩展名
    // @param: strPath     文件名, 如: D:\Software\HxDPortableSetup.exe
    // @param: bHasDot     是否包含点号
    // @ret: 文件夹        如 exe
    static _tstring GetFileExt(const _tstring& strPath, bool bHasDot = false);

    // 
    // @brief: 获取短路径
    // @param: strPath     输入长路径(必须存在)
    // @ret: 短路径
    static _tstring GetShortPath(const _tstring& strPath);

    // 
    // @brief: 获取长路径
    // @param: strPath     输入短路径(必须存在)
    // @ret: 长路径
    static _tstring GetLongPath(const _tstring& strPath);

    // 
    // @brief: 获取全路径
    // @param: strPath     输入路径
    // @ret: 全路径
    static _tstring GetFullPath(const _tstring& strPath);

    //
    // @brief: DOS路径转Nt路径
    // @param: strPath      路径
    // @ret: _tstring       Win32 样式的 NT 路径
    static _tstring DosPathToNtPath(const _tstring& strPath);

    //
    // @brief: Nt路径转DOS路径
    // @param: strPath      路径
    // @ret: _tstring       DOS路径
    static _tstring NtPathToDosPath(const _tstring& strPath);

    //
    // @brief: 获取路径属性
    // @param: strPath      路径
    // @ret: 成功返回true
    static bool GetAttributes(const _tstring& strPath, DWORD& dwAttr);

    //
    // @brief: 设置路径属性
    // @param: strPath      路径
    // @ret: 成功返回true
    static bool SetAttributes(const _tstring& strPath, const DWORD& dwAttr);

    //
    // @brief: 获取文件大小
    // @param: strPath      路径
    // @ret: 文件大小
    static unsigned long long GetFileSize(const _tstring& strPath);

    // 
    // @brief: 检查是否为文件
    // @param: strPath      文件名, 如: D:\Software\HxDPortableSetup.exe
    // @ret: 是否存在       存在返回 true
    static bool IsArchive(const _tstring& strPath);

    // 
    // @brief: 检查是否为文件夹
    // @param: strPath      文件名, 如: D:\Software\HxDPortableSetup.exe
    // @ret: 是否存在       存在返回 true
    static bool IsDirectory(const _tstring& strPath);

    // 
    // @brief: 检查路径是否存在
    // @param: strPath      文件名, 如: D:\Software\HxDPortableSetup.exe
    // @ret: 是否存在       存在返回 true
    static bool IsExist(const _tstring& strPath);

    // 
    // @brief: 检查路径是否隐藏
    // @param: strPath      文件名, 如: D:\Software\HxDPortableSetup.exe
    // @ret: 是否存在       存在返回 true
    static bool IsHidden(const _tstring& strPath);

    // 
    // @brief: 检查路径是否只读
    // @param: strPath      文件名, 如: D:\Software\HxDPortableSetup.exe
    // @ret: 是否存在       只读返回 true
    static bool IsReadonly(const _tstring& strPath);

    // 
    // @brief: 判断是否是完整路径
    // @param: strPath      文件名, 如: D:\Software\HxDPortableSetup.exe
    // @ret: 是返回 true
    static bool IsFullPath(const _tstring& strPath);

    // 
    // @brief: 获取从 strSrc 到 strDest 的相对路径
    // @param: strDest      路径目标
    // @param: strSrc       基于路径源
    // @ret: 是返回 _tstring   相对路径
    static _tstring GetRelativePath(const _tstring& strDest, const _tstring& strSrc, bool bFromIsDir = true);

    // 
    // @brief: 判断是否是相对路径
    // @param: strPath
    // @ret: 是返回 true
    static bool IsRelative(const _tstring& strPath);

    // 
    // @brief: 判断是否是绝路径
    // @param: strPath
    // @ret: 是返回 true
    static bool IsAbsolutePath(const _tstring& strPath);

    // 
    // @brief: 如果路径存在空格, 则使用引号括起来
    // @param: strPath      文件名, 如: C:\Program Files (x86)
    // @ret: 添加引号       添加引号返回 true
    static bool QuoteSpaces(_tstring& strPath);

    // 
    // @brief: 删除路径开头和末尾的引号
    // @param: strPath      文件名, 如: "C:\Program Files (x86)"
    // @ret: 去除引号       去除引号返回 true
    static bool UnquoteSpaces(_tstring& strPath);

    //
    // @brief: 获取相对路径的绝对路径
    // @param: strPath      文件(夹)相对路径
    // @ret: _tstring       转换后的绝对路径
    static _tstring GetAbsolutePath(const _tstring& strPath);

    //
    // @brief: 重命名(夹)
    // @param: strSrc       原始文件名
    // @param: strDest      目标文件名(绝对路径或仅目标名)
    // @ret: 成功返回true
    static bool Rename(const _tstring& strSrc, const _tstring& strDest);

    //
    // @brief: 移动文件(夹)
    // @param: strSrc       原始文件名
    // @param: strDest      目标文件名(绝对路径或仅目标名)
    // @ret: 成功返回true
    static bool Move(const _tstring& strSrc, const _tstring& strDest);

    //
    // @brief: 拷贝文件(夹)
    // @param: strSrc       源路径
    // @param: strDest      目的路径(末尾为'\'则认为是复制到文件夹)
    // @param: bEmptyDir    是否拷贝空文件夹
    // @param: bOverwrites  是否覆盖文件
    // @param: depth        目录深度 如: 0：指定目录为根目录, 遍历0层子目录 
    // @ret: 成功返回true
    static bool Copy(
        const _tstring& strSrc, 
        const _tstring& strDest, 
        bool bEmptyDir = true, 
        bool bOverwrites = false,
        int32_t depth = MAX_PATH
    );

    //
    // @brief: 拷贝文件夹
    // @param: strSrc       源文件夹
    // @param: strDest      目的文件夹
    // @param: bEmptyDir    是否拷贝空文件夹
    // @param: bOverwrites  是否覆盖文件
    // @param: depth        目录深度 如: 0：指定目录为根目录, 遍历0层子目录 
    // @ret: 成功返回true
    static bool CopyDir(
        const _tstring& strSrc, 
        const _tstring& strDest, 
        bool bEmptyDir = true, 
        bool bOverwrites = false,
        int32_t depth = MAX_PATH
    );

    //
    // @brief: 删除文件或文件夹
    // @param: strPath      路径
    // @ret: 成功返回true
    static bool Delete(const _tstring& strPath);

    //
    // @brief: 删除文件
    // @param: strPath      路径
    // @ret: 成功返回true
    static bool DeleteArchive(const _tstring& strPath);

    //
    // @brief: 删除目录(递归删除子目录及文件)
    // @param: strPath      路径
    // @ret: 成功返回true
    static bool DeleteDir(const _tstring& strPath);

    //
    // @brief: 创建目录(递归)
    // @param: strPath      路径
    // @ret: 成功返回true
    static bool CreateDir(const _tstring& strPath);

    //
    // @brief: 拷贝文件(夹)(使用SHFileOperation)
    // @param: strSrcPath   源路径
    // @param: strDestPath  目的路径(末尾为'\'则认为是复制到文件夹)
    // @ret: 错误代码       成功返回0
    static int SHCopy(const _tstring& strSrc, const _tstring& strDest);

    //
    // @brief: 重命名(夹)(使用SHFileOperation)
    // @param: strSrc       原始文件名
    // @param: strDest      目标文件名(绝对路径或仅目标名)
    // @ret: 错误代码       成功返回0
    static int SHMove(const _tstring& strSrc, const _tstring& strDest);

    //
    // @brief: 移动文件(夹)(使用SHFileOperation)
    // @param: strSrc       原始文件名
    // @param: strDest      目标文件名(绝对路径或仅目标名)
    // @ret: 错误代码       成功返回0
    static int SHRename(const _tstring& strSrc, const _tstring& strDest);

    //
    // @brief: 删除文件(使用SHFileOperation)
    // @param: strPath      路径
    // @ret: 错误代码       成功返回0
    static int SHDelete(const _tstring& strSrc);

    //
    // @brief: 获取展开环境变量字符串
    // @param: strPath      路径
    // @ret: _tstring       展开字符串
    static _tstring GetExpandEnvStrings(const _tstring& strPath);

    //
    // @brief: 获取环境变量字符串
    // @param: strPath      路径
    // @ret: _tstring       展开字符串
    static _tstring GetUnExpandEnvStrings(const _tstring& strPath);

    //
    // @brief: 获取目录下文件路径
    // @param: fileList     文件路径字符串容器
    // @param: strDir       指定目录
    // @param: extList      扩展名过滤列表, 如: {("exe"), ("txt")}
    // @param: bIncludeHide 是否包含隐藏文件
    // @param: depth        目录深度 如: 0：指定目录为根目录, 遍历0层子目录 
    // @param: bIgnoreCase  是否忽略扩展名过滤大小写
    // @ret: std::vector<_tstring> 文件路径列表
    static std::vector<_tstring> GetFileList(
        const _tstring& strDir,
        const std::vector<_tstring>& extList = {},
        bool bIncludeHide = false,
        int32_t depth = MAX_PATH,
        bool bIgnoreCase = true
    );

    //
    // @brief: 获取目录下子目录
    // @param: fileList     文件信息容器
    // @param: strDir       指定目录
    // @param: bIncludeHide 是否包含隐藏文件
    // @param: depth        目录深度 如: 0：指定目录为根目录, 遍历0层子目录 
    // @ret: std::vector<_tstring>  子目录列表
    static std::vector<_tstring> GetDirList(
        const _tstring& strDir,
        bool bIncludeHide = false,
        int32_t depth = MAX_PATH
    );

    //
    // @brief: 获取符合搜索要求的文件路径
    // @param: fileList     文件路径字符串容器
    // @param: strDir       指定目录
    // @param: extList      扩展名过滤列表, 如: {("exe"), ("txt")}
    // @param: bIncludeHide 是否包含隐藏文件
    // @param: depth        目录深度 如: 0：指定目录为根目录, 遍历0层子目录 
    // @param: bIgnoreCase  是否忽略扩展名过滤大小写
    // @ret: std::vector<_tstring> 文件路径列表
    static std::vector<_tstring> SearchFiles(
        const _tstring& strFile,
        const _tstring& strSrcName,
        bool bIncludeHide = false,
        int32_t depth = MAX_PATH
    );

private:

    //
    // @brief: 获取目录下文件路径
    // @param: fileList     文件路径字符串容器
    // @param: strDir          指定目录
    // @param: extList      扩展名过滤列表, 如: {("exe"), ("txt")}
    // @param: bIncludeHide 是否包含隐藏文件
    // @param: depth        目录深度 如: 0：指定目录为根目录, 遍历0层子目录 
    // @param: bIgnoreCase  是否忽略扩展名过滤大小写
    // @ret: void
    static void _GetFileList(
        std::vector<_tstring>& fileList,
        const _tstring& strDir,
        const std::vector<_tstring>& extList = {},
        bool bIncludeHide = false,
        int32_t depth = MAX_PATH,
        bool bIgnoreCase = true
    );

    //
    // @brief: 获取目录下子目录
    // @param: fileList     文件信息容器
    // @param: strDir       指定目录
    // @param: bIncludeHide 是否包含隐藏文件
    // @param: depth        目录深度 如: 0：指定目录为根目录, 遍历0层子目录 
    // @ret: void
    static void _GetDirList(
        std::vector<_tstring>& fileList,
        const _tstring& strDir,
        bool bIncludeHide = false,
        int32_t depth = MAX_PATH
    );

    //
    // @brief: 获取符合搜索要求的文件路径
    // @param: fileList     文件路径字符串容器
    // @param: strSrcDir    指定目录
    // @param: strSrcName   文件名
    // @param: bIncludeHide 是否包含隐藏文件
    // @param: depth        目录深度 如: 0：指定目录为根目录, 遍历0层子目录 
    // @param: bIgnoreCase  是否忽略扩展名过滤大小写
    // @ret: void
    static void _SearchFiles(
        std::vector<_tstring>& fileList,
        const _tstring& strSrcDir,
        const _tstring& strSrcName,
        bool bIncludeHide = false,
        int32_t depth = MAX_PATH
    );

};